<?php
/*
 * @Description    : 安全
 * @Version        : 1.0.0
 * @Author         : QianLong
 * @Date           : 2021-04-25 15:46:17
 * @LastEditors    : QianLong
 * @LastEditTime   : 2021-05-30 22:35:27
 */

namespace app\common\logic;

use app\common\service\QlRedis;
use app\lib\exception\ApiException;
use think\facade\Db;

class Security
{
    /**
     * 安全频率控制
     */
    public static function limit_check($uid, $refresh_key = '', $redis = null)
    {
        $minuteLimit = 100; //每分钟最大限制次数
        if (empty($redis)) {
            $redis = new QlRedis();
        }
        $ip = get_client_ip();
        $cacheTTL = $redis->ttl('secure:check:ip:' . $ip);
        if ($cacheTTL === -1 || $cacheTTL > 60) {
            $redis->del('secure:check:ip:' . $ip);
        }
        // 校验IP维度的次数
        $hasIpCount = $redis->exists('secure:check:ip:' . $ip);
        if ($hasIpCount) {
            $ipCount = $redis->get('secure:check:ip:' . $ip);
            // 超过频率限制
            if ($ipCount > $minuteLimit) {
                if (!empty($refresh_key)) {
                    $redis->del('refresh:key:' . $refresh_key);
                }
                throw new ApiException('访问过于频繁，已被强制退出，请重新登录，并注意访问频率 [ErrorCode:1003]', -401);
            } else {
                $redis->incr('secure:check:ip:' . $ip);
            }
        } else {
            $redis->set('secure:check:ip:' . $ip, 1, 60);
        }
        // 校验用户维度的次数
        if ($uid > 0) {
            $cacheTTL = $redis->ttl('secure:check:uid:' . $uid);
            if ($cacheTTL === -1 || $cacheTTL > 60) {
                $redis->del('secure:check:uid:' . $uid);
            }
            $hasUidCount = $redis->exists('secure:check:uid:' . $uid);
            if ($hasUidCount) {
                $uidCount = $redis->get('secure:check:uid:' . $uid);
                // 超过频率限制
                if ($uidCount > $minuteLimit) {
                    if (!empty($refresh_key)) {
                        $redis->del('refresh:key:' . $refresh_key);
                    }
                    $redis->del('token-' . $uid);
                    throw new ApiException('访问过于频繁，已被强制退出，请重新登录，并注意访问频率 [ErrorCode:1004]', -401);
                } else {
                    $redis->incr('secure:check:uid:' . $uid);
                }
            } else {
                $redis->set('secure:check:uid:' . $uid, 1, 60);
            }
        }
    }
    /**
     * token刷新限制
     */
    public static function token_refresh_limit($uid, $redis = null)
    {
        if (empty($redis)) {
            $redis = new QlRedis();
        }
        $hasUidCount = $redis->exists('secure:refresh:limit:' . $uid);
        if ($hasUidCount) {
            $uidCount = $redis->get('secure:refresh:limit:' . $uid);
            // 超过频率限制
            if ($uidCount > 3) {
                $redis->del('secure:refresh:limit:' . $uid);
                throw new ApiException('刷新过于频繁，已被强制退出，请重新登录', -401);
            } else {
                $redis->incr('secure:refresh:limit:' . $uid);
                return true;
            }
        } else {
            $loginExpireTime = config('app.SYS_STATIC.login_expire');
            $redis->set('secure:refresh:limit:' . $uid, 1, $loginExpireTime);
            return true;
        }
        throw new ApiException('登录已过期，请重新登录 [ErrorCode:1007]', -2);
    }
    /**
     * token刷新
     */
    public static function token_refresh($refresh_key, $redis = null)
    {
        if (empty($refresh_key)) {
            throw new ApiException('登录已过期，请重新登录 [ErrorCode:1006]', -2);
        }
        if (empty($redis)) {
            $redis = new QlRedis();
        }
        // 校验用户维度的次数
        $hasUidCount = (int)$redis->exists('refresh:key:' . $refresh_key);
        if ($hasUidCount < 1) {
            throw new ApiException('登录已过期，请重新登录 [ErrorCode:1004]', -2);
        }
        $cacheUser = $redis->get('refresh:key:' . $refresh_key);
        $cacheUser = json_decode($cacheUser, true);
        $payload['uid']       = $cacheUser['uid'];
        $payload['password']       = $cacheUser['password'];
        $payload['loginTime'] = $cacheUser['loginTime'];
        $payload['refresh_key'] = createId();
        $token = think_encrypt(json_encode($payload));
        //用户登录有效期
        $loginRefreshExpireTime = config('app.SYS_STATIC.login_refresh_expire');
        $loginExpireTime = config('app.SYS_STATIC.login_expire');
        // 存储用户刷新token
        $redis->set('token-' . $cacheUser['uid'], $token, $loginExpireTime);
        $redis->set('refresh:key:' . $payload['refresh_key'], json_encode($payload), $loginRefreshExpireTime);
        $redis->del('refresh:key:' . $refresh_key);
    }
}
